﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

//常用案例
namespace ConsoleApp
{
    internal class Delegate
    {
        static void Main1(string[] args)
        {
            ProductFactory productFactory = new ProductFactory();
            WrapFactory   wrapFactory = new WrapFactory();
            Logger logger = new Logger();

            Func<Product> func = new Func<Product>(productFactory.MakePizza);
            Func<Product> func1 = new Func<Product>(productFactory.MakeToyCar);
            Action<Product> action = new Action<Product>(logger.Log);
            Box box1 =wrapFactory.WrapProduct(func,action);
            Box box2 =wrapFactory.WrapProduct(func1, action);
            Console.WriteLine(box1.Product.Name);
            Console.WriteLine(box2.Product.Name);
        }
        
    }
    class Logger
    {
        public void Log(Product product)
        {
            Console.WriteLine("Product {0} created at {1},Price is {2}", product.Name,DateTime.Now,product.Price);
        }
    }
    class Product
    {
        public string Name { get; set; }
        public double Price { get; set; }
    }
    class Box
    {
        public Product Product { get; set; }
    }
    class WrapFactory
    {
        public Box WrapProduct(Func<Product> getProduct,Action<Product> logCallback)
        {
            Box box = new Box();
            Product product = getProduct.Invoke();
            if (product.Price > 50)
            {
                logCallback(product);
            }
            box.Product = product;
            return box;
        }
    }
    class ProductFactory 
    {
        public Product MakePizza()
        {
            Product product = new Product();
            product.Name = "Pizza";
            product.Price = 12;
            return product;
        }
        public Product MakeToyCar() 
        {
            Product product = new Product();
            product.Name = "ToyCar";
            product.Price=100;
            return product;
        }
    }

}

//有无返回值的委托
namespace Delegate
{
    class Program
    {
        static void Main11(string[] args)
        {
            Caculator caculator = new Caculator();
            Action action = new Action(caculator.Report);//无返回值
            action();
            Func<int, int, int> func = new Func<int, int, int>(caculator.Add);//有返回值
            Func<int, int, int> func1 = new Func<int, int, int>(caculator.Sub);
            int x = 200;
            int y = 100;
            int z = 0;
            z = func(x, y);
            Console.WriteLine(z);
            z = func1(x, y);
            Console.WriteLine(z);
        }
        class Caculator
        {
            public void Report()
            {
                Console.WriteLine("I have 3 methods");
            }
            public int Add(int a, int b)
            {
                int result = a + b;
                return result;
            }
            public int Sub(int a, int b)
            {
                int result = a - b;
                return result;
            }
        }
    }
}

//自定义委托
namespace DIYDelegate
{
    public delegate double Calc(double x,double y);
    class Program
    {
        static void Main12(string[] args)
        {
            Caculator caculator1 = new Caculator();
            Calc calc = new Calc(caculator1.Add);
            Calc calc1 = new Calc(caculator1.Sub);
            Calc calc2 = new Calc(caculator1.Mul);
            Calc calc3 = new Calc(caculator1.Div);
            double x = 100;
            double y = 200;
            double z = 0;
            z = calc(x, y);
            Console.WriteLine(z);
            z = calc1(x, y);
            Console.WriteLine(z);
            z = calc2(x, y);
            Console.WriteLine(z);
            z = calc3(x, y);
            Console.WriteLine(z);
        }
    }
    class Caculator
    {
        public double Add(double a, double b) { return a + b; }
        public double Sub(double a, double b) { return a - b; }
        public double Mul(double a, double b) { return a * b; }
        public double Div(double a, double b) { return a / b; }
    } 
}

//多播委托
namespace MultiCast
{
    class Program
    {
        static void Main1(string[] args)
        {
            Student student1 = new Student() { Id = 1,PenColor = ConsoleColor.Red};
            Student student2 = new Student() { Id = 2,PenColor = ConsoleColor.Yellow};
            Student student3 = new Student() { Id = 3,PenColor = ConsoleColor.Blue};
            Action action1 = new Action(student1.DoHomework);
            Action action2 = new Action(student2.DoHomework);
            Action action3 = new Action(student3.DoHomework);
            //单播委托
            //action();
            //action1();
            //action2();
            //多播委托
            action1 += action2;
            action1 += action3;
            action1();
        }
    }
    class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public ConsoleColor PenColor { get; set; }
        public void DoHomework()
        {
            for (int i = 0; i < 5; i++) 
            {
                Console.ForegroundColor = this.PenColor;
                Console.WriteLine("Student {0} doing homework {1} hour(s)", this.Id, i);
                Thread.Sleep(1000);
            }
        }
    }
}

//隐式异步调用
namespace Async
{
    //同步调用是在单线程里进行串行调用
    //异步调用是在多线程里进行并行调用
    class Program
    {
        static void Main1(string[] args)
        {
            Student student1 = new Student() { Id = 1, PenColor = ConsoleColor.Red };
            Student student2 = new Student() { Id = 2, PenColor = ConsoleColor.Yellow };
            Student student3 = new Student() { Id = 3, PenColor = ConsoleColor.Blue };
            //直接同步调用
            //student1.DoHomework();
            //student2.DoHomework();
            //student3.DoHomework();

            //间接同步调用,多播委托也是间接同步调用
            //Action action1 = new Action(student1.DoHomework);
            //Action action2 = new Action(student2.DoHomework);
            //Action action3 = new Action(student3.DoHomework);
            //action1();
            //action2();
            //action3();

            //隐式异步调用,多线程（ .NET Core 和 .NET 5+ 以上版本不再支持异步调用）
            //Action action1 = new Action(student1.DoHomework);
            //Action action2 = new Action(student2.DoHomework);
            //Action action3 = new Action(student3.DoHomework);
            //action1.BeginInvoke(null,null);
            //action2.BeginInvoke(null,null);
            //action3.BeginInvoke(null,null);

            //显示异步调用
            //(1)
            Thread thread1 = new Thread(student1.DoHomework);
            Thread thread2 = new Thread(student2.DoHomework);
            Thread thread3 = new Thread(student3.DoHomework);
            thread1.Start();
            thread2.Start();
            thread3.Start();
            //(2)
            /*Task task1 = new Task(new Action(student1.DoHomework));
            Task task2 = new Task(new Action(student2.DoHomework));
            Task task3 = new Task(new Action(student3.DoHomework));
            task1.Start();
            task2.Start();
            task3.Start();*/

            for (int i = 0; i < 10; i++) 
            {
                Console.ForegroundColor= ConsoleColor.Cyan;
                Console.WriteLine("Main thread {0}",i);
                Thread.Sleep(1000);
            }
        }
    }
    class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public ConsoleColor PenColor { get; set; }
        public void DoHomework()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.ForegroundColor = this.PenColor;
                Console.WriteLine("Student {0} doing homework {1} hour(s)", this.Id, i);
                Thread.Sleep(1000);
            }
        }
    }

}

//接口取代委托
namespace IDelegate
{
    internal class Delegate
    {
        static void Main1(string[] args)
        {
            IProductFactory productFactory = new PizzaFactory();
            IProductFactory productFactory1 = new ToyCarFactory();
            WrapFactory wrapFactory = new WrapFactory();

            

            Box box1 = wrapFactory.WrapProduct(productFactory);
            Box box2 = wrapFactory.WrapProduct(productFactory1);

            Console.WriteLine(box1.Product.Name);
            Console.WriteLine(box2.Product.Name);
        }

    }
    interface IProductFactory
    {
        Product Make();
    }
    class PizzaFactory : IProductFactory
    {
        public Product Make()
        {
            Product product = new Product();
            product.Name = "Pizza";
            return product;
        }
    }
    class ToyCarFactory : IProductFactory
    {
        public Product Make()
        {
            Product product = new Product();
            product.Name = "ToyCar";
            return product;
        }
    }

    class Product
    {
        public string Name { get; set; }
        public double Price { get; set; }
    }
    class Box
    {
        public Product Product { get; set; }
    }
    class WrapFactory
    {
        public Box WrapProduct(IProductFactory productFactory)
        {
            Box box = new Box();
            Product product = productFactory.Make();
            box.Product = product;
            return box;
        }
    }

}
